package set

import "github.com/DiracLee/dires-go/ds/dict"

type Consumer func(elem string) bool

type naiveSet interface {
	Len() int
	Add(val string) int
	Remove(val string) int
	Has(val string) bool
	ToSlice() []string
	ForEach(consumer Consumer) bool
	RandomMembers(limit int) []string
	RandomDistinctMembers(limit int) []string
	Clear()
}

type naiveSetImpl struct {
	d dict.Dict
}

// newNaiveSet returns a naive set that has no inter-set operation.
func newNaiveSet(d dict.Dict) naiveSet {
	return &naiveSetImpl{d: d}
}

// Len returns number of elements.
func (s *naiveSetImpl) Len() int {
	return s.d.Len()
}

// Add an element with `val`.
func (s *naiveSetImpl) Add(val string) int {
	return s.d.PutOrSet(val, struct{}{})
}

// Remove the element with `val`.
func (s *naiveSetImpl) Remove(val string) int {
	return s.d.Remove(val)
}

// Has judges if there are any element with `val`.
func (s *naiveSetImpl) Has(val string) bool {
	_, exists := s.d.Get(val)
	return exists
}

// ToSlice returns a slice that contains all elements.
func (s *naiveSetImpl) ToSlice() []string {
	elems := make([]string, 0, s.Len())
	s.d.ForEach(func(key string, val interface{}) bool {
		elems = append(elems, key)
		return true
	})
	return elems
}

// ForEach consumes element one by one with `consumer` until all elements run out or any consumer returns false;
//         returns whether all consumers return true.
func (s *naiveSetImpl) ForEach(consumer Consumer) bool {
	return s.d.ForEach(func(key string, val interface{}) bool {
		return consumer(key)
	})
}

// RandomMembers returns `limit` elements, which may be duplicated.
func (s *naiveSetImpl) RandomMembers(limit int) []string {
	return s.d.RandomKeys(limit)
}

// RandomDistinctMembers returns at most `limit` elements, which are distinct.
func (s *naiveSetImpl) RandomDistinctMembers(limit int) []string {
	return s.d.RandomDistinctKeys(limit)
}

// Clear remove all elements.
func (s *naiveSetImpl) Clear() {
	s.d.Clear()
}